package com.bingxue.edu.management.education.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.bingxue.edu.common.enums.CommonStatusEnum;
import com.bingxue.edu.common.enums.EnrollStatusEnum;
import com.bingxue.edu.framework.common.model.PageQuery;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.framework.mybatis.base.BaseService;
import com.bingxue.edu.management.education.mapper.StudentMapper;
import com.bingxue.edu.management.education.model.entity.Parent;
import com.bingxue.edu.management.education.model.entity.Student;
import com.bingxue.edu.management.education.model.query.StudentQuery;
import com.bingxue.edu.management.education.model.req.StudentCreateReq;
import com.bingxue.edu.management.education.model.req.StudentUpdateReq;
import com.bingxue.edu.management.education.model.resp.StudentCount;
import com.bingxue.edu.management.education.model.resp.StudentDetailResp;
import com.bingxue.edu.management.education.model.resp.StudentResp;
import com.bingxue.edu.management.education.model.resp.StudentScheduleResp;
import com.bingxue.edu.management.education.model.resp.StudentStatResp;
import com.bingxue.edu.management.shop.mapper.OrderMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.bingxue.edu.management.education.model.entity.table.EnrollmentTableDef.ENROLLMENT;
import static com.bingxue.edu.management.education.model.entity.table.ParentTableDef.PARENT;
import static com.bingxue.edu.management.education.model.entity.table.StudentTableDef.STUDENT;
import static com.bingxue.edu.management.shop.model.entity.table.OrderTableDef.ORDER;


/**
 * 学生管理实现类
 *
 * @author zq
 * @since 2024/08/19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StudentService extends BaseService<StudentMapper, Student> {

    private final ParentService parentService;
    private final LessonService lessonService;
    private final EnrollmentService enrollmentService;
    private final OrderMapper orderMapper;

    @Transactional(rollbackFor = Exception.class)
    public void create(StudentCreateReq req) {
        Student existStudent = getByNameAndPhone(req.getName(), req.getParentPhone());
        ValidationUtils.throwIfNotNull(existStudent, "学生信息已存在");
        Student newStudent = this.copy(req);
        String pinyin = PinyinUtil.getPinyin(newStudent.getName(), "");
        newStudent.setNamePinyin(pinyin);
        newStudent.setEnrollStatus(EnrollStatusEnum.NO_ENROLL);

        //1. 根据手机号判断该学生是否已经创建了家长账号
        Parent parent = parentService.getByPhone(req.getParentPhone());
        if (parent == null) {
            //2. 家长账号不存在则创建
            parent = new Parent();
            parent.setName(req.getParentName());
            parent.setMobilePhone(req.getParentPhone());
            parent.setUsername(req.getParentPhone());
            parent.setStatus(CommonStatusEnum.ENABLED);
            parent.setPassword(DigestUtil.bcrypt(RandomUtil.randomString(8)));
            parentService.save(parent);
        }
        newStudent.setParentId(parent.getId());
        this.save(newStudent);
        log.info("创建学员成功, {}", newStudent);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(StudentUpdateReq req, String id) {
        Student oldStudent = this.getById(id);
        ValidationUtils.throwIfNull(oldStudent, "学生信息不存在");
        if (req.getName() != null && !req.getName().equals(oldStudent.getName())) {
            String pinyin = PinyinUtil.getPinyin(req.getName(), "");
            oldStudent.setNamePinyin(pinyin);
        }
        BeanUtil.copyProperties(req, oldStudent, CopyOptions.create().ignoreNullValue());
        this.updateById(oldStudent);

        log.info("更新学员[{}]信息成功, {}", id, req);
    }

    public StudentDetailResp getDetailById(String id) {
        return this.queryChain().where(STUDENT.ID.eq(id)).oneAs(StudentDetailResp.class);
    }

    /**
     * 学员数量统计
     */
    public StudentStatResp getStatData() {
        StudentStatResp studentStatResp = new StudentStatResp();

        // 学员总数
        Long totalCount = this.count();
        studentStatResp.setTotalCount(totalCount);

        // 今日新增人数
        long todayCount = this.queryChain().where(STUDENT.CREATE_TIME.ge(LocalDate.now())).count();
        studentStatResp.setTodayCount(todayCount);

        // 各状态人数
        Map<EnrollStatusEnum, Long> countMap = this.queryChain()
                .select(STUDENT.ENROLL_STATUS, QueryMethods.count().as("count"))
                .groupBy(STUDENT.ENROLL_STATUS)
                .listAs(StudentCount.class)
                .stream().collect(Collectors.toMap(StudentCount::getEnrollStatus, StudentCount::getCount));

        studentStatResp.setNoEnrollCount(countMap.get(EnrollStatusEnum.NO_ENROLL));
        studentStatResp.setOnStudyCount(countMap.get(EnrollStatusEnum.ON_STUDY));
        studentStatResp.setFinishedCount(countMap.get(EnrollStatusEnum.FINISHED));

        return studentStatResp;
    }

    public List<StudentScheduleResp> getScheduleByStudentId(String id) {
        return lessonService.getScheduleByStudentId(id);
    }

    public List<StudentResp> getListByParentId(String parentId) {
        return this.queryChain().where(STUDENT.PARENT_ID.eq(parentId)).listAs(StudentResp.class);
    }

    /**
     * 根据学生id根据学生状态为已报名
     */
    public void updateStudentStatus(String studentId, EnrollStatusEnum status) {
        this.updateChain().set(STUDENT.ENROLL_STATUS, status).where(STUDENT.ID.eq(studentId)).update();
    }

    /**
     * 根据名字和家长电话查找学生id
     */
    public Student getByNameAndPhone(String studentName, String parentPhone) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(STUDENT.ID)
                .from(STUDENT)
                .where(STUDENT.NAME.eq(studentName))
                .and(STUDENT.PARENT_PHONE.eq(parentPhone));
        return this.getOne(queryWrapper);
    }


    /**
     * 查询学员分页信息 ,包含推荐人
     */
    public Page<StudentResp> getStudentPage(StudentQuery query, PageQuery pageQuery) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                        .select(STUDENT.ALL_COLUMNS, PARENT.RECOMMENDER)
                        .from(STUDENT)
                        .where(STUDENT.NAME.like(query.getKeyword()).or(STUDENT.PARENT_PHONE.like(query.getKeyword())).or(STUDENT.NAME_PINYIN.like(query.getKeyword())))
                        .and(STUDENT.ENROLL_STATUS.eq(query.getEnrollStatus()))
                        .and(STUDENT.ADMISSION_YEAR.eq(query.getAdmissionYear()))
                        .leftJoin(PARENT).on(PARENT.ID.eq(STUDENT.PARENT_ID))
                        .orderBy(STUDENT.ID, false);
        return this.pageAs(pageQuery.toPage(), queryWrapper, StudentResp.class);

    }

    /**
     * 根据id列表删除学员
     * 没有任何报名信息,订单信息的学员才允许删除
     * @param ids 学员id列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeStudentsByIds(List<String> ids) {
        for (String studentId:ids){
            //判断是否有报名信息
            QueryWrapper enrollQueryWrapper = QueryWrapper.create()
                    .select(ENROLLMENT.ALL_COLUMNS)
                    .from(ENROLLMENT)
                    .where(ENROLLMENT.STUDENT_ID.eq(studentId));
            ValidationUtils.throwIf(enrollmentService.exists(enrollQueryWrapper),"学员存在报名信息,不可删除");

            //判断是否有订单信息
            ValidationUtils.throwIfNotEmpty(orderMapper.selectListByCondition(ORDER.STUDENT_ID.eq(studentId)),"学员存在订单信息,不可删除");
            this.removeById(studentId);
        }
    }
}
